package org.ix.shiro.config;

import org.ix.shiro.shiro.IxAuthenticatingFilter;
import org.ix.shiro.shiro.IxAuthorizingRealm;

import org.aopalliance.intercept.Joinpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class IxShiroConfiguration {

    @Bean("securityManager")
    public SecurityManager securityManager(IxAuthorizingRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, AuthProperties authProperties) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        // 验证过滤
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("ix", new IxAuthenticatingFilter());
        shiroFilter.setFilters(filters);

        Map<String, String> filterMap = new LinkedHashMap<>();
        for (String url : authProperties.getAnonymousUrls()) {
            filterMap.put(url, "anon");
        }
        filterMap.put("/account/login", "anon");
        filterMap.put("/**", authProperties.isClose() ? "anon" : "ix");
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager, AuthProperties authProperties) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        // 跳过shiro权限验证
        if (authProperties.isClose()) {
            // 将 AuthorizationAttributeSourceAdvisor 构造函数中设置的 advice (类型为 AopAllianceAnnotationsAuthorizingMethodInterceptor)覆盖
            MethodInterceptor advice = Joinpoint::proceed;
            advisor.setAdvice(advice);
        }
        return advisor;
    }

    @Bean
    public FilterRegistrationBean<Filter> shiroFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //该值缺省为false，表示生命周期由SpringApplicationContext管理，设置为true则表示由ServletContainer管理
        registration.addInitParameter("targetFilterLifecycle", "true");
        registration.setEnabled(true);
        registration.setOrder(Integer.MAX_VALUE - 1);
        registration.addUrlPatterns("/*");
//        registration.setOrder(1);
        return registration;
    }
}
